/*---------------------------------------------------------------------------
	ZaRan	-	A Totallly Automatic CFD Software
	Copyright (C) ,Since 2020
-------------------------------------------------------------------------------
License
	This file is part of ZaRan.

!	@file		multigrid.h
!	@brief	the purpose of this file.
!	@author	Chen Jie.
\*---------------------------------------------------------------------------*/
#include"grid/include/multigrid.h"
#include<iostream>
void MultiGrid::SetGridDim(int dim)
{
	for (size_t iGrid = 0; iGrid < GetGridNum(); ++iGrid)
	{
		gridVec_[iGrid].SetDim(dim);
	}
}
void MultiGrid::SetGridDim(size_t iGrid, int dim)
{
	gridVec_[iGrid].SetDim(dim);
}
void MultiGrid::SetGridIndex(size_t iGrid, size_t index)
{
	gridVec_[iGrid].SetIndex(index);
}
void MultiGrid::SetGridList(vector<Grid>& gridVec)
{
	std::swap(gridVec_, gridVec);
}
void MultiGrid::SetInterNode()
{
	//all inter nodes
	vector<GridNode*>interNodeVec;

	//find inter nodes from all boundary nodes
	for (size_t iGrid = 0; iGrid < GetGridNum(); ++iGrid)
	{
		for (size_t iBound = 0; iBound < GetBoundNodeNum(iGrid); ++iBound)
		{
			size_t iNode = GetBoundNodeIndex(iGrid, iBound);
			if (*GetNodeType(iGrid, iNode) == BoundType::interface)
			{
				interNodeVec.emplace_back(GetGridNode(iGrid, iNode));
			}
		}
	}
	// Method I: Search from all grid nodes! Good but slow!
	// For Chimera Grid Must choose this method
	int internodeNum = interNodeVec.size();
	for (size_t iNode = 0; iNode < internodeNum; ++iNode)
	{
		GridNode& localNode = *interNodeVec[iNode];
		Point& localNodeCoord = *localNode.GetCoord();
		Grid& parentGrid = *interNodeVec[iNode]->GetGridPtr();
		size_t nodeIndex = interNodeVec[iNode]->GetIndex();
		// radius of neibor nodes pool
		double neiborPoolRadius = localNode.GetNeiborPoolRadius() * 1.1;
		for (size_t jGrid = 0; jGrid < GetGridNum(); ++jGrid)
		{
			for (size_t jNode = 0; jNode < GetNodeNum(jGrid); ++jNode)
			{
				Point jNodeCoord = *GetNodeCoord(jGrid, jNode);
				double dis = distance(localNodeCoord, jNodeCoord);
				// outside of neibor nodes pool 
				if (dis > neiborPoolRadius)
					continue;
				localNode.AddNeiborNode(GetGridNode(jGrid, jNode));
			}
		}
	}


	// Method II: Search from other inter nodes! Bad but fast!
//int internodeNum = internode_index.size();
//for (size_t iNode = 0; iNode < internodeNum; ++iNode)
//{
//	Point internode_coord = GetNodeCoord(internode_grid_index[iNode], internode_index[iNode]);
//	vector<int>neibor_node_index = GetNeiborNodeIndex(internode_grid_index[iNode], internode_index[iNode]);
//	vector<int>neibor_node_grid_index = GetNeiborNodeGridIndex(internode_grid_index[iNode], internode_index[iNode]);
//	vector<Grid*>neibor_node_grid = GetNeiborNodeGrid(internode_grid_index[iNode], internode_index[iNode]);
//	double ref_dis = -LARGE_NUMBER;
//	for (size_t iNeib = 0; iNeib < GetNeiborNodeNum(internode_grid_index[iNode], internode_index[iNode]); ++iNeib)
//	{
//		Point neibor_coord = GetNodeCoord(neibor_node_grid_index[iNeib], neibor_node_index[iNeib]);
//		ref_dis = std::max(ref_dis, distance(internode_coord, neibor_coord));
//	}
//	ref_dis *= 1.1;
//	for (size_t jNode = 0; jNode < internodeNum; jNode++)
//	{
//		if (iNode == jNode)
//			continue;
//		Point jNodeCoord = GetNodeCoord(internode_grid_index[jNode], internode_index[jNode]);
//		double dis = distance(internode_coord, jNodeCoord);
//		if (internode_grid_index[iNode] > internode_grid_index[jNode] && dis <= SMALL_NUMBER)
//		{
//			neibor_node_index = internode_neibor_node_index[jNode];
//			neibor_node_grid = internode_neibor_node_grid[jNode];
//			break;
//		}
//		else if (dis < ref_dis)
//		{
//			vector<int>temp_neibor_node_index = GetNeiborNodeIndex(internode_grid_index[jNode], internode_index[jNode]);
//			vector<int>temp_neibor_node_grid_index = GetNeiborNodeGridIndex(internode_grid_index[jNode], internode_index[jNode]);
//			vector<Grid*>temp_neibor_node_grid = GetNeiborNodeGrid(internode_grid_index[jNode], internode_index[jNode]);
//			temp_neibor_node_grid_index.push_back(internode_grid_index[jNode]);
//			temp_neibor_node_index.push_back(internode_index[jNode]);
//			temp_neibor_node_grid.push_back(&gridVec_[internode_grid_index[jNode]]);
//			size_t itemp, iNeib;
//			for (itemp = 0; itemp < temp_neibor_node_index.size(); itemp++)
//			{
//				// has same coordinate with current node,continue
//				if (GetNodeCoord(temp_neibor_node_grid_index[itemp], temp_neibor_node_index[itemp]) == GetNodeCoord(internode_grid_index[iNode], internode_index[iNode]))
//					continue;
//				for (iNeib = 0; iNeib < neibor_node_index.size(); ++iNeib)
//				{
//					if (temp_neibor_node_grid_index[itemp] == neibor_node_grid_index[iNeib] && temp_neibor_node_index[itemp] == neibor_node_index[iNeib])
//						break;
//					// has the same coordinate with exist neibor node
//					if (GetNodeCoord(temp_neibor_node_grid_index[itemp], temp_neibor_node_index[itemp]) == GetNodeCoord(neibor_node_grid_index[iNeib], neibor_node_index[iNeib]))
//					{
//						if (temp_neibor_node_grid_index[itemp] < neibor_node_grid_index[iNeib])
//						{
//							neibor_node_grid_index[iNeib] = temp_neibor_node_grid_index[itemp];
//							neibor_node_grid[iNeib] = temp_neibor_node_grid[itemp];
//							neibor_node_index[iNeib] = temp_neibor_node_index[itemp];
//						}
//						break;
//					}
//				}
//				if (iNeib == neibor_node_index.size())
//				{
//					neibor_node_grid_index.push_back(temp_neibor_node_grid_index[itemp]);
//					neibor_node_grid.push_back(temp_neibor_node_grid[itemp]);
//					neibor_node_index.push_back(temp_neibor_node_index[itemp]);
//				}
//			}
//		}
//	}
//	internode_neibor_node_index[iNode] = neibor_node_index;
//	internode_neibor_node_grid[iNode] = neibor_node_grid;
//}
	//for (size_t iNode = 0; iNode < internodeNum; ++iNode)
	//{
	//	SetNeiborNode(internode_grid_index[iNode], internode_index[iNode], internode_neibor_node_index[iNode], internode_neibor_node_grid[iNode]);
	//}
}



void MultiGrid::OutGrid(std::ostream& fout)
{
	fout << "variables = x, y, z, neibornum" << std::endl;
	for (size_t iGrid = 0; iGrid < GetGridNum(); ++iGrid)
	{
		fout << "Zone" << std::endl;
		for (size_t iNode = 0; iNode < GetNodeNum(iGrid); ++iNode)
		{
			auto& pt = *GetNodeCoord(iGrid, iNode);
			fout << pt.x() << "  " << pt.y() << "  " << pt.z() << "  " << GetNeiborNodeNum(iGrid, iNode) << std::endl;
		}
	}
}
void MultiGrid::ReorderNeiborNode()
{
	for (size_t iGrid = 0; iGrid < GetGridNum(); ++iGrid)
	{
		gridVec_[iGrid].ReorderNeiborNode();
	}

}
void MultiGrid::CalCoordTrans()
{
	for (size_t iGrid = 0; iGrid < GetGridNum(); ++iGrid)
	{
		gridVec_[iGrid].CalCoordTrans();
	}

}